#include "self_hal/QCY_Chargebox/QCY_chargeBox.h"
#include "debug.h"
#define LOG_TAG "[QCY_CHARGE]"


static void charge_box_send_message(u8 data)
{
    int msg[1];
    msg[0] = data; 
    logln_pos();
    os_taskq_post_type("app_core",MSG_FROM_QCY_CHARGEBOX, 1, msg);
}

#define CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS 4
#define CHARGE_COMMUNICATION_MIN_TABLE(bitLength) \
{bitLength - CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*2 - CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*3 - CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*4 - CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*5 - CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*6 - CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
150 - CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS,}

#define CHARGE_COMMUNICATION_MAX_TABLE(bitLength) \
{bitLength + CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*2 + CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*3 + CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*4 + CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*5 + CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
bitLength*6 + CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS, \
150 + CHARGE_COMMUNICATION_TIME_ERROR_ALLOW_MS,}

const u8 chargeBoxCompareTable[2][7] = 
{
    CHARGE_COMMUNICATION_MIN_TABLE(20), // bitLength = 20ms
    CHARGE_COMMUNICATION_MAX_TABLE(20)
};

/**
 * @brief 
 * @param  deltaTime        delta time
 * @return u8 `0:Invalid`;`1~6: bitNum`; `7:slience area` ;`8:Reset signal`
 * @author zhengziyang (zhengziyang@zh-jieli.com)
 */
static u8 chargeBoxBitNumTranslate(u16 deltaTime)
{
    // logln_info("deltaTime:%u", deltaTime);
    if(deltaTime > 250)
    {
        return 8;
    }
    for(int i=0; i<7; i++)
    {
        if(deltaTime < chargeBoxCompareTable[1][i])
        {
            if(deltaTime > chargeBoxCompareTable[0][i])
            {
                return i+1;
            }
            return 0;
        }
    }
    log_info("No match:%d",deltaTime);
    return 0;
}
/**
 * @brief 清楚记录信息，帧错误或接收完成
 * @author zhengziyang (zhengziyang@zh-jieli.com)
 */
#define CHARGE_BOX_PAHSE_CLEAN() \
data = 0; \
dataRecievedCount = 0; \
isDecoding = false

void chargeBoxPhase(P33_IO_WKUP_EDGE edge)
{
    static u32 lastTime,isDecoding = 0,deltaT;
    static u16 data=0,dataRecievedCount=0;
#ifdef  TEST_TRIGGER_MECS
    /**************************************************************** */
    static u32 test_mesc_last;
    /**************************************************************** */
#endif

#define DATA_BIT_NUM 12
    u8 bitNum;
    u8 ret;

#ifdef  TEST_TRIGGER_MECS
    /**************************************************************** */
    logln_info("trigger:%u",jiffies_msec() - test_mesc_last);
    test_mesc_last = jiffies_msec();
    /**************************************************************** */
#endif
    if(isDecoding == false)
    {
        if(edge==RISING_EDGE)
        {
            lastTime = jiffies_msec();
            isDecoding = true;
        }
        return;
    }
    else
    {
        deltaT = jiffies_msec() - lastTime;
        lastTime += deltaT;
        bitNum = chargeBoxBitNumTranslate(deltaT);
        if(bitNum == 0) //no index matched
        {
            CHARGE_BOX_PAHSE_CLEAN();
            return;
        }
        else if(bitNum == 7) //150ms
        {
            if(edge == FALLING_EDGE)
            {
                CHARGE_BOX_PAHSE_CLEAN();
            }
            return;
        }
        else if(bitNum == 8) // over 300ms
        {
            if(edge == RISING_EDGE)
            {
                data = 0;
                dataRecievedCount = 0;
            }
            else
            {
                CHARGE_BOX_PAHSE_CLEAN();
            }
            return;
        }
        else{
            // do next code
        }

        for(int i=0;i<bitNum;i++)
        {
            data <<= 1;

            switch(edge)
            {
                case FALLING_EDGE:data |= 0x01;break;
                case RISING_EDGE:data &= ~0x01;break;
                default:break;
            }
            dataRecievedCount++;
            if(dataRecievedCount > DATA_BIT_NUM)
            {
                CHARGE_BOX_PAHSE_CLEAN();
                return;
            }
        }
        if(dataRecievedCount == DATA_BIT_NUM)
        {
            data >>= 1;
            // log_info("recieved data u16:%04X",data);
            ret = (u8)(data & 0x000f);
            data>>=2;
            // log_info("recieved data u16:%04X",data);
            ret |= (u8)(data & 0x00f0);
            // logln_info("Output data:%02x",data);
            if(((ret & 0xf0)>>4) == ((ret & 0x0f))){ // Check frame format
                charge_box_send_message(ret & 0x0f);
            }
            CHARGE_BOX_PAHSE_CLEAN();
            return;
        }
    }
}

enum 
{
    QCY_CHARGEBOX_MSG_OPEN_CAP = 1,    // uncap
    QCY_CHARGEBOX_MSG_CLOSE_CAP   = 2, // cap
    QCY_CHARGEBOX_MSG_CLEAR_PAIRED_KEY = 3,
    QCY_CHARGEBOX_MSG_START_PAIR  = 5,
    QCY_CHARGEBOX_MSG_ENTRY_DUT   = 6,
    QCY_CHARGEBOX_MSG_RESET       = 10, //0x0A
};


void QCY_charge_box_message_handler(int *msg)
{
    switch(msg[0])
    {
        case QCY_CHARGEBOX_MSG_OPEN_CAP:logln_info("OPEN_CAP");break;
        case QCY_CHARGEBOX_MSG_CLOSE_CAP:logln_info("CLOSE_CAP");break;
        case QCY_CHARGEBOX_MSG_CLEAR_PAIRED_KEY:logln_info("CLEAR_PAIRED_KEY");break;
        case QCY_CHARGEBOX_MSG_START_PAIR:logln_info("START_PAIR");break;
        case QCY_CHARGEBOX_MSG_ENTRY_DUT:logln_info("ENTRY_DUT");break;
        case QCY_CHARGEBOX_MSG_RESET:logln_info("RESET");break;
        default:logln_info("UNKNOWN_MSG");break;
    }
}

APP_MSG_HANDLER(qcy_charge_box_msg_handler) = 
{
    .owner = 0xff,
    .from = MSG_FROM_QCY_CHARGEBOX,
    .handler = QCY_charge_box_message_handler
};